/*******************************************************************************
 * Copyright (c) 2000, 2018 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.ui.views.bookmarkexplorer;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.viewers.IBasicPropertyConstants;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Control;

/*
*
* Marked for deletion, see Bug 550439
*
* @noreference
* @noinstantiate This class is not intended to be instantiated by clients.
* @noextend This class is not intended to be subclassed by clients.
*/
@Deprecated
/**
 * Provides content for the bookmark navigator
 */
class BookmarkContentProvider implements IStructuredContentProvider,
		IResourceChangeListener, IBasicPropertyConstants {

	private IResource input;

	private Viewer viewer;

	/**
	 * The constructor.
	 */
	public BookmarkContentProvider(BookmarkNavigator bookmarksView) {
		super();
	}

	/**
	 * The visual part that is using this content provider is about
	 * to be disposed. Deallocate all allocated SWT resources.
	 */
	@Override
	public void dispose() {
		IResource resource = (IResource) viewer.getInput();
		if (resource != null) {
			resource.getWorkspace().removeResourceChangeListener(this);
		}
	}

	/**
	 * Returns all the bookmarks that should be shown for
	 * the current settings.
	 */
	Object[] getBookmarks(IResource resource) {
		try {
			return resource.findMarkers(IMarker.BOOKMARK, true,
					IResource.DEPTH_INFINITE);
		} catch (CoreException e) {
			return new Object[0];
		}
	}

	public Object[] getChildren(Object element) {
		// If the input element is a workbench return a list
		// of the existing bookmarks.  Otherwise, return an empty list.
		if (element instanceof IResource) {
			return getBookmarks((IResource) element);
		}
		return new Object[0];
	}

	@Override
	public Object[] getElements(Object element) {
		return getChildren(element);
	}

	/**
	 * Recursively walks over the resource delta and gathers all marker deltas.  Marker
	 * deltas are placed into one of the three given vectors depending on
	 * the type of delta (add, remove, or change).
	 */
	void getMarkerDeltas(IResourceDelta delta, List<IMarker> additions, List<IMarker> removals, List<IMarker> changes) {
		for (IMarkerDelta markerDelta : delta.getMarkerDeltas()) {
			IMarker marker = markerDelta.getMarker();
			switch (markerDelta.getKind()) {
			case IResourceDelta.ADDED:
				if (markerDelta.isSubtypeOf(IMarker.BOOKMARK)) {
					additions.add(marker);
				}
				break;
			case IResourceDelta.REMOVED:
				if (markerDelta.isSubtypeOf(IMarker.BOOKMARK)) {
					removals.add(marker);
				}
				break;
			case IResourceDelta.CHANGED:
				if (markerDelta.isSubtypeOf(IMarker.BOOKMARK)) {
					changes.add(marker);
				}
				break;
			}
		}

		//recurse on child deltas
		for (IResourceDelta child : delta.getAffectedChildren()) {
			getMarkerDeltas(child, additions, removals, changes);
		}
	}

	/*
	 * Method declared on ITreeContentProvider,
	 */
	public Object getParent(Object element) {
		return input;
	}

	/**
	 * hasChildren method comment.
	 */
	public boolean hasChildren(Object element) {
		if (element instanceof IWorkspace) {
			return true;
		}
		return false;
	}

	@Override
	public void inputChanged(Viewer newViewer, Object oldInput, Object newInput) {
		if (oldInput == null) {
			IResource resource = (IResource) newInput;
			resource.getWorkspace().addResourceChangeListener(this);
		}
		this.viewer = newViewer;
		this.input = (IResource) newInput;
	}

	/**
	 * The workbench has changed.  Process the delta and provide updates to the viewer,
	 * inside the UI thread.
	 *
	 * @see IResourceChangeListener#resourceChanged
	 */
	@Override
	public void resourceChanged(final IResourceChangeEvent event) {

		// gather all marker changes from the delta.
		// be sure to do this in the calling thread,
		// as the delta is destroyed when this method returns
		final List<IMarker> additions = new ArrayList<>();
		final List<IMarker> removals = new ArrayList<>();
		final List<IMarker> changes = new ArrayList<>();

		IResourceDelta delta = event.getDelta();
		if (delta == null) {
			return;
		}
		getMarkerDeltas(delta, additions, removals, changes);

		// update the viewer based on the marker changes, in the UI thread
		if (additions.size() + removals.size() + changes.size() > 0) {
			viewer.getControl().getDisplay().asyncExec(() -> {
				// This method runs inside an asyncExec.  The widget may have been destroyed
				// by the time this is run.  Check for this and do nothing if so.
				Control ctrl = viewer.getControl();
				if (ctrl == null || ctrl.isDisposed()) {
					return;
				}

				viewer.refresh();
			});
		}
	}
}
